package hotel.quartz.oversea.job.switchs;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import hotel.base.oversea.constant.ApiConstans;
import hotel.base.oversea.constant.CommonConstants;
import hotel.base.oversea.constant.CommonUrlConstants;
import hotel.base.oversea.constant.SwitchConstants;
import hotel.base.oversea.constant.quartz.UrlSwitchsEnums;
import hotel.base.oversea.utils.Result;
import hotel.quartz.oversea.config.service.RedisService;
import hotel.quartz.oversea.entity.form.JobForm;
import hotel.quartz.oversea.job.base.BaseJob;
import hotel.quartz.oversea.service.JobAndTriggerService;
import hotel.quartz.oversea.util.JobRestTemplateUtils;
import hotel.quartz.oversea.vo.switchs.SwitchCityInfoVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 *  Switch City Info Job
 * </p>
 *
 * @description: Switch City Info Job
 * @author: qiuyy
 * @date: 2020-05-26 13:22
 * @version: V1.0
 */
@Slf4j
public class SwitchCityInfoJob implements BaseJob {
    private String redisSwCityPageIndex = SwitchConstants.REDIS_SWITCHS_CITY_PAGE_INDEX;
    private String jobGroupName = SwitchConstants.JOB_GROUP_NAME_SWITCHS;
    private String jobClassName = this.getClass().getName();
    private int pageSize = ApiConstans.SW_CITY_PAGE_SIZE;
    private String timestamp = "Scij"+String.valueOf(System.currentTimeMillis());
    private int thisRedisCount = SwitchConstants.REDIS_SW_CITY_WAIT_COUNT;
    private String redisWaitSaveKey = SwitchConstants.REDIS_SW_CITY_WAIT_SAVE;


    @Autowired
    private JobAndTriggerService jobAndTriggerService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedisService redisService;
    @Autowired
    private RestTemplate restTemplate;

    /**
     * pageSize最大100
     *
     * 结果：获取中国国内城市信息，第三方参数指定页码pageSize，结果可能为空，最后一页可能返回空不属于异常
     *
     *
     * @param jobExecutionContext
     */
    @Override
    @SneakyThrows
    public void execute(JobExecutionContext jobExecutionContext) {
        log.info("Switch City Info Job {} >>>>>>>> 携程城市获取执行时间: {}", timestamp, DateUtil.now());// 0/10 0 17 * * ?    */10 * * * * ?
        String accessToken ="";
        //String host = CommonUrlConstants.SWITCHS_HOST;
        String host= CommonUrlConstants.SWITCHS_ONLINE_HOST;
        String hotelMethodGetUrl = host + UrlSwitchsEnums.city.GET.getValue();
        String saveUrl = host + UrlSwitchsEnums.city.SAVE.getValue();//+"?access_token="+accessToken;
        boolean check = checkSaveRedisData(saveUrl);
        if(!check){
            String pageIndex = getPageIndex();
            //业务参数
            String countryId = "1";//中国
            Map<String,Object> map = new HashMap<>();
//            map.put("access_token",accessToken);
            map.put("countryID",countryId);
            map.put("currentPageIndex",pageIndex);
            map.put("pageSize",String.valueOf(pageSize));
            requestCityApi(hotelMethodGetUrl,saveUrl,map,accessToken,pageIndex);
        }
        log.info("Switch City Info Job {} >>>>>>>> 携程城市获取结束时间: {},{}",timestamp, DateUtil.now());
    }

    /**
     * 校验是否需要保存缓存的数据
     * @param saveUrl
     * @return
     */
    private boolean checkSaveRedisData(String saveUrl) {
        log.info("Switch City Info Job {} 携程城市信息定时器进入方法 checkSaveRedisData",timestamp);
        Map<String,List<SwitchCityInfoVo>> getInfos = getRedisWaitData();
        if(null != getInfos && getInfos.size()>=thisRedisCount){
            //缓存酒店数据达到大于等于thisRedisCount，则执行保存到数据库操作，可能大于thisRedisCount比如数据操作保存失败还原加入到redis
            boolean result = requestSaveWaitDataApi(saveUrl,getInfos);
            if(result){
                return true;
            }else{
                return false;
            }
        }else{
            return false;
        }
    }
    /**
     * 调用保存缓存数据集合接口
     * @param saveUrl
     * @param redisWaitDataSaveMap
     * @return
     */
    private boolean requestSaveWaitDataApi(String saveUrl,Map<String,List<SwitchCityInfoVo>> redisWaitDataSaveMap) {
        if(null == redisWaitDataSaveMap || redisWaitDataSaveMap.size()==0){
            log.warn("Switch City Info Job {} 携程城市信息进入方法 requestSaveWaitDataApi 待保存数据redisWaitDataSaveMap为空",timestamp);
            return true;
        }
        log.info("Switch City Info Job {} 携程城市信息进入方法 requestSaveWaitDataApi",timestamp);
        Map map = new HashMap();
        map.put("switchCityInfoVosMap",redisWaitDataSaveMap);
        //调用前,删除当前缓存的酒店数据，让下一次定时器正常查询上游接口。若调用结果失败则还原加入缓存
        deleteRedisWaitSaveData();
        //发起请求
        Result response = JobRestTemplateUtils.post(saveUrl, JSON.toJSONString(map),restTemplate);
        if(response.getCode()== CommonConstants.SUCCESS){
            log.info("Switch City Info Job {} requestSaveWaitDataApi 保存数据成功",timestamp);
            return true;
        }else{
            log.error("Switch City Info Job {} requestSaveWaitDataApi 异常错误: {}",timestamp, JSON.toJSONString(response));
            backPutRedisWaitSaveData(redisWaitDataSaveMap);
            return false;
        }
    }

    /**
     * 请求携程城市获取接口
     */
    public void requestCityApi(String url,String saveUrl,Map<String,Object> paramsMap,String accessToken,String pageIndex){
        log.info("Switch City Info Job {} 携程城市获取进入方法requestCityApi: {},{},{}",timestamp,pageIndex, JSON.toJSONString(paramsMap),accessToken);
        //发起请求
        String r = null;
        String params = "?countryID={countryID}&currentPageIndex={currentPageIndex}&pageSize={pageSize}";//access_token={access_token}&
        try{
            r = restTemplate.getForObject(url +params , String.class,paramsMap);
        }catch (Exception e){
            log.error("Switch City Info Job {} 携程城市信息 requestSaveWaitDataApi 发起请求 异常 catch: {},{},{}",
                    timestamp,url, JSON.toJSONString(paramsMap),r);
            log.error(e.getMessage(),e);
        }

        Result response = JSON.parseObject(r, Result.class);

        if(null != response && response.getCode()== CommonConstants.SUCCESS){
            if(null != response.getData()){
                //响应结果
                JSONObject vo = JSON.parseObject(JSON.toJSONString(response.getData()));
                String infoStr = vo.getString("cityInfoList");
                if(!StringUtils.isEmpty(infoStr)){
                    List<SwitchCityInfoVo> cityList = null;
                    try{
                        cityList = JSON.parseObject(vo.getString("cityInfoList"), List.class);
                    }catch (Exception e){
                        log.error(e.getMessage(),e);
                    }
                    if(null != cityList && cityList.size()>0){
                        //查询到数据，存入redis
                        Map dataMap = new HashMap();
                        dataMap.put(UUID.randomUUID().toString(),cityList);
                        boolean setResultRedis = setPutRedisWaitData(dataMap);
                        if(setResultRedis){
                            //有数据就暂定为还有下一页
                            setPageIndex(String.valueOf(Integer.valueOf(pageIndex)+1));
                        }else{
                            //更新失败，不更新标识，下一次定时器继续查询当前
                            log.error("Switchs Hotel Info Job {} 携程城市定时器 setResultRedis 异常错误: {},{}",timestamp,response, JSON.toJSONString(paramsMap));
                        }

                    }else{
                        //已无数据，提交保存redis数据，结束暂停定时器
                        saveRedisWaitDateAndEndingJob(saveUrl);
                    }
                }else{
                    //该页数据，已无数据，提交保存redis数据，结束暂停定时器
                    saveRedisWaitDateAndEndingJob(saveUrl);
                }
            }else{
                //该页数据，已无数据，提交保存redis数据，结束暂停定时
                saveRedisWaitDateAndEndingJob(saveUrl);
            }

        }else{
            log.error("Switch City Info Job 获取携程城市获取异常错误: {},{}",response, JSON.toJSONString(paramsMap));
        }
    }
    /**
     * 删除缓存的待保存数据
     * @return
     */
    public void deleteRedisWaitSaveData(){
        log.info("Switch City Info Job {} 携程城市信息进入方法 deleteRedisWaitSaveData 删除当前携程城市信息定时器数据缓存",timestamp);
        redisTemplate.delete(redisWaitSaveKey);
    }
    /**
     * 还原追加回去待保存数据
     * @return
     */
    public void backPutRedisWaitSaveData(Map<String,List<SwitchCityInfoVo>> redisWaitDataMap){
        log.info("Switch City Info Job {} 携程城市信息进入方法 backPutRedisWaitSaveData 还原追加当前酒店信息缓存 ",timestamp);
        //还原redis数据
        Map<String,List<SwitchCityInfoVo>> getRedisMap = (Map<String,List<SwitchCityInfoVo>>)redisService.get(redisWaitSaveKey);
        if(null != getRedisMap && getRedisMap.size()>0){
            getRedisMap.putAll(redisWaitDataMap);
        }else{
            getRedisMap = redisWaitDataMap;
        }
        redisService.set(redisWaitSaveKey,getRedisMap);
    }
    /**
     * 获取保存在缓存中的待save的数据
     */
    private Map<String,List<SwitchCityInfoVo>> getRedisWaitData() {
        return (Map<String,List<SwitchCityInfoVo>>)redisService.get(redisWaitSaveKey);
    }
    /**
     * 成功请求酒店房型接口后，合法酒店房型数据，追加进缓存中
     */
    private boolean setPutRedisWaitData(Map<String, List<Long>> mapRealRoomVoMap) {
        Map<String,List<Long>> getRedisMap = (Map<String,List<Long>>)redisService.get(redisWaitSaveKey);
        if(null != getRedisMap && getRedisMap.size()>0){
            getRedisMap.putAll(mapRealRoomVoMap);
        }else{
            getRedisMap = mapRealRoomVoMap;
        }
        boolean result = redisService.set(redisWaitSaveKey,getRedisMap);
        return result;
    }

    /**
     * 结束定时器,更新保存缓存的数据
     * @param saveUrl
     */
    public void saveRedisWaitDateAndEndingJob(String saveUrl){
        //提交保存缓存信息
        boolean re = requestSaveWaitDataApi(saveUrl,getRedisWaitData());
        if(re){
            JobForm jobForm = new JobForm();
            jobForm.setJobClassName(jobClassName);
            jobForm.setJobGroupName(jobGroupName);
            try {
                jobAndTriggerService.pauseJob(jobForm);
                log.warn("Switch City Info Job {} 最后一页暂停job: {}",timestamp, JSON.toJSONString(jobForm));
                deletePageIndex();
            } catch (SchedulerException e) {
                log.error("Switch City Info Job {} 最后一页暂停job异常: {}",timestamp, JSON.toJSONString(jobForm));
                log.error(e.getMessage(),e);
            }
        }else{
            log.error("Switchs Hotel Info Job {} 最后一页保存操作 异常错误: {},{}",timestamp);
        }

    }
    public void setPageIndex(String pageIndex){
        redisTemplate.opsForValue().set(redisSwCityPageIndex,pageIndex);
    }
    private String getPageIndex() {
        //pageIndex
        String pageIndex = (String)redisTemplate.opsForValue().get(redisSwCityPageIndex);
        if(null==pageIndex){
            //首次请求数据
            pageIndex = "1";//从1开始 当前页码
        }
        return pageIndex;
    }
    public void deletePageIndex(){
        redisTemplate.delete(redisSwCityPageIndex);
    }

}
